/**********************************************************************
*file:数据文件
*author:残梦
*versions:V1.0
*date:2025.7.23
*note:
**********************************************************************/
#include "cmsis_os.h"
#include "data.h"
#include "common_driver.h"
#include "adc.h"
#include "memory.h"
#include "protocol_config_driver.h"

typedef struct
{
    FileFormatContent_SystemConfiguration_StructDef config;
    bool CalibrationDataUse;//假-不使用校准数据;真-使用校准数据
    FileFormatContent_User_StructDef DeviceData;//设备采样数据
}SystemConfig_StructDef;

static SystemConfig_StructDef SystemConfig;

/****************************************************
@function:读取设备采样数据
@param:temperature:温度,单位℃
    concentration:浓度
    VoltageTemperature:温度检测电压,单位V
    VoltageHydrogen:氢气检测电压,单位V
@return:void
@note:
****************************************************/
void Data_DeviceSampleResult_Get(float *temperature,float *concentration,float *VoltageTemperature,float *VoltageHydrogen)
{
    *temperature = SystemConfig.DeviceData.temperature;
    *concentration = SystemConfig.DeviceData.concentration;
    *VoltageTemperature = SystemConfig.DeviceData.VoltageTemperature;
    *VoltageHydrogen = SystemConfig.DeviceData.VoltageHydrogen;
}

/****************************************************
@function:重置系统参数
@param:void
@return:void
@note:
****************************************************/
void Data_SystemRestore(void)
{
    FileFormatContent_SystemConfiguration_StructDef config = {.address = 0};
    Memory_FileLineNumber_Write(eMemory_FileObject_SystemConfiguration,1);
    Memory_FileContent_Write(eMemory_FileObject_SystemConfiguration,0,(void *)(&config),1);

    Memory_FileLineNumber_Write(eMemory_FileObject_User0,0);
    Memory_FileLineNumber_Write(eMemory_FileObject_VoltageTemperature,0);
    Memory_FileLineNumber_Write(eMemory_FileObject_VoltageHydrogen,0);
}

/****************************************************
@function:获取设备地址
@param:void
@return:地址值
@note:
****************************************************/
uint8_t Data_DeviceAddress_Get(void){return SystemConfig.config.address;}

/****************************************************
@function:设置设备地址
@param:void
@return:地址值
@note:
****************************************************/
void Data_DeviceAddress_Set(uint8_t address)
{
    if(address >= eDeviceAddress_Master)return;//非法地址
    if(!Memory_FileContent_Read(eMemory_FileObject_SystemConfiguration,0,(void *)(&SystemConfig.config),1))Data_SystemRestore();
    SystemConfig.config.address = address;
    Memory_FileContent_Write(eMemory_FileObject_SystemConfiguration,0,(void *)(&SystemConfig.config),1);
}

/****************************************************
@function:设置采样数据是否使用校准数据
@param:enable:假-不使用校准数据;真-使用校准数据
@return:void
@note:
****************************************************/
void Data_CalibrationDataUse_Set(bool enable)
{
    SystemConfig.CalibrationDataUse = enable;
    if(!enable)
    {
        SystemConfig.DeviceData.temperature = 0.0f;
        SystemConfig.DeviceData.concentration =  0.0f;
    }
}

/****************************************************
@function:获取采样数据是否使用校准数据
@param:void
@return:假-不使用校准数据;真-使用校准数据
@note:
****************************************************/
bool Data_CalibrationDataUse_Get(void){return SystemConfig.CalibrationDataUse;}

/****************************************************
@function:加载校准数据
@param:void
@return:void
@note://使用eMemory_FileObject_User0文件计算校准系数eMemory_FileObject_VoltageTemperature、eMemory_FileObject_VoltageHydrogen文件
文件中浓度值必须从小变大:如下所示
序号	温度(℃)	浓度(ppm)	温度电压(V)	氢气电压(V)
0	20	100	    0.2	0.5
1	20	400	    0.2	0.7
2	20	600	    0.2	0.8
3	20	1000    0.2 0.9 
4	25	100	    2	1.2//新的温度段校准
5	25	400	    2	1.4
6	25	600	    2	1.6
7	25	1000	2	1.8
8	30	100	    3	2//新的温度段校准
9	30	400	    3	2.2
10	30	600	    3	2.5
11	30	1000	3	2.7

****************************************************/
void Data_CalibrationLoad(void)
{
    Data_CalibrationDataUse_Set(false);osDelay(1);
    uint16_t LineNumber = Memory_FileLineNumber_Read(eMemory_FileObject_User0);
    Memory_FileLineNumber_Write(eMemory_FileObject_VoltageTemperature,0);
    Memory_FileLineNumber_Write(eMemory_FileObject_VoltageHydrogen,0);
    if(LineNumber < 2){Data_CalibrationDataUse_Set(true);return;}

    FileFormatContent_User_StructDef user0;
    FileFormatContent_CalibrationData_StructDef CalibrationData,CalibrationDataH2;
    double temperature[2] = {0.0,0.0};
    double concentration[2] = {0.0,0.0};
    double VoltageTemperature[2] = {0.0,0.0};
    double VoltageHydrogen[2] = {0.0,0.0};
    double a = 0.0,b = 0.0;
	uint16_t i = 0;
    double TemperatureMin = 0.0;

    for(i = 0;i < LineNumber;i++)
    {
        Memory_FileContent_Read(eMemory_FileObject_User0,i,(void *)(&user0),1);
        //dData_LOG("%d %.3f %.3f %.3f %.3f\n",\
        //    user0.SerialNumber,\
        //    user0.temperature,\
        //    user0.concentration,\
        //    user0.VoltageTemperature,\
        //    user0.VoltageHydrogen);
        temperature[1] = temperature[0];temperature[0] = user0.temperature;
        concentration[1] = concentration[0];concentration[0] = user0.concentration;
        VoltageTemperature[1] = VoltageTemperature[0];VoltageTemperature[0] = user0.VoltageTemperature;
        VoltageHydrogen[1] = VoltageHydrogen[0];VoltageHydrogen[0] = user0.VoltageHydrogen;
        if(i < 1)continue;

        //计算温度电压对温度的系数
        Common_LinearFitCoefficient(&a,&b,VoltageTemperature,temperature,2);
        CalibrationData.SerialNumber = i-1;
        CalibrationData.value = 0.0f;
        CalibrationData.real = VoltageTemperature[1];
        CalibrationData.a = a;
        CalibrationData.b = b;
        Memory_FileContent_Write(eMemory_FileObject_VoltageTemperature,CalibrationData.SerialNumber,(void *)(&CalibrationData),1);
        
        //计算氢气电压对氢气浓度的系数
        if(i == 1)TemperatureMin = temperature[1];
        CalibrationDataH2.SerialNumber = i-1;
        if(concentration[0] < concentration[1])
        {
            CalibrationDataH2.real = VoltageHydrogen[1];
            Memory_FileContent_Write(eMemory_FileObject_VoltageHydrogen,CalibrationDataH2.SerialNumber,(void *)(&CalibrationDataH2),1);
            TemperatureMin = temperature[0];
            continue;
        }
        Common_LinearFitCoefficient(&a,&b,VoltageHydrogen,concentration,2);
        CalibrationDataH2.value = TemperatureMin;
        CalibrationDataH2.real = VoltageHydrogen[1];
        CalibrationDataH2.a = a;
        CalibrationDataH2.b = b;
        Memory_FileContent_Write(eMemory_FileObject_VoltageHydrogen,CalibrationDataH2.SerialNumber,(void *)(&CalibrationDataH2),1);
    }
    Memory_FileLineNumber_Write(eMemory_FileObject_VoltageTemperature,i-1);
    Memory_FileLineNumber_Write(eMemory_FileObject_VoltageHydrogen,i-1);
    Data_CalibrationDataUse_Set(true);

    //Memory_FileDataPrintf(eMemory_FileObject_VoltageTemperature);
    //Memory_FileDataPrintf(eMemory_FileObject_VoltageHydrogen);
    dData_LOG("CalibrationData load finish\n");
}

/****************************************************
@function:校准计算:温度电压对温度
@param:
    value:待计算值
    pos:使用校准数据时对应行pos值
@return:温度
@note:
****************************************************/
float Data_CalibrationCalculate_VoltageTemperature(float voltage,uint16_t *pos)
{
    uint16_t LineNumber = 0,i = 0;
    FileFormatContent_CalibrationData_StructDef data,data_end;
    bool polarity = false;
    float Temp = 0.0f;

    LineNumber = Memory_FileLineNumber_Read(eMemory_FileObject_VoltageTemperature);
    Memory_FileContent_Read(eMemory_FileObject_VoltageTemperature,LineNumber-1,(void *)(&data_end),1);

    for(i = 0;i < LineNumber;i++)
    {
        Memory_FileContent_Read(eMemory_FileObject_VoltageTemperature,i,(void *)(&data),1);
        if(i == 0)polarity = (data.real < data_end.real)?true:false;//判断温度和电压关系
        if(polarity)//真(正相关:温度越大电压越大)
        {
            if(voltage > data.real)continue;
        }
        else//假(负相关:温度越大电压越小)
        {
            if(voltage < data.real)continue;
        }

        *pos = (i == 0)?i:(i - 1);
        Memory_FileContent_Read(eMemory_FileObject_VoltageTemperature,*pos,(void *)(&data),1);
        Temp = voltage * data.a + data.b;
        //dData_LOG("Vt:pos=%d y=ax+b:%.3f = %.3f*%.3f + %.3f\n",\
        //    *pos,Temp,voltage,data.a,data.b);
        break;
    }
    return Temp;
}

/****************************************************
@function:校准计算:氢气电压对浓度
@param:
    value:待计算值
    pos:使用对应行校准数据
@return:浓度
@note:
****************************************************/
float Data_CalibrationCalculate_VoltageHydrogen(float voltage,uint16_t pos)
{
    float concentration = 0.0f;
    uint16_t LineNumber = Memory_FileLineNumber_Read(eMemory_FileObject_VoltageHydrogen);
    if((pos >= LineNumber) || (LineNumber == 0))return concentration;
    FileFormatContent_CalibrationData_StructDef data;
    uint32_t Tmin = 0,start_pos = 0;
    float real_start = 0.0f;
    bool polarity = false,flag = false;

    //依据当前位置的温度下限向上找浓度段起点pos位置
    Memory_FileContent_Read(eMemory_FileObject_VoltageHydrogen,pos,(void *)(&data),1);
    Tmin = (uint32_t )(data.value*10000);
    while(pos)
    {
        Memory_FileContent_Read(eMemory_FileObject_VoltageHydrogen,--pos,(void *)(&data),1);
        if(Tmin != (uint32_t )(data.value*10000)){pos++;break;}
    }
    start_pos = pos;
    //dData_LOG("Tmin=%.3f pos=%d\n",Tmin/10000.0f,pos);

    //查找浓度电压匹配位置
    Memory_FileContent_Read(eMemory_FileObject_VoltageHydrogen,pos,(void *)(&data),1);
    if(pos < (LineNumber-1))
    {
        for(flag = false,real_start = data.real;(pos < LineNumber);)
        {
            Memory_FileContent_Read(eMemory_FileObject_VoltageHydrogen,++pos,(void *)(&data),1);//从下一行开始读取
            if(Tmin != (uint32_t )(data.value*10000)){pos--;break;}//判断同温度段校准区域
            if(!flag){flag = true;polarity = (data.real > real_start)?true:false;}//判断浓度和电压关系

            //dLOG("pos=%d polarity=%d voltage=%.3f real=%.3f\n",pos,polarity,voltage,data.real);
            if(polarity){if(voltage > data.real)continue;}//真(正相关:浓度越大电压越大)
            else{if(voltage < data.real)continue;}//假(负相关:浓度越大电压越小)
            pos--;break;
        }
        if(pos == LineNumber)pos--;
        Memory_FileContent_Read(eMemory_FileObject_VoltageHydrogen,pos,(void *)(&data),1);
    }

    concentration = voltage * data.a + data.b;
    //dData_LOG("Vh2:Tmin[start_pos=%d]=%.3f pos=%d y=ax+b:%.3f = %.3f*%.3f + %.3f\n",\
    //    start_pos,(Tmin/10000.0f),pos,concentration,voltage,data.a,data.b);
    return concentration;
}

/****************************************************
@function:数据加载
@param:void
@return:void
@note:
****************************************************/
void Data_Init(void)
{
    SystemConfig.CalibrationDataUse = true;//默认使用校准数据
    if(!Memory_FileContent_Read(eMemory_FileObject_SystemConfiguration,0,(void *)(&SystemConfig.config),1))Data_SystemRestore();
}

/****************************************************
@function:设备采样
@param:void
@return:void
@note:
****************************************************/
void Data_DeviceSample(void)
{
    uint16_t pos = 0;
    float temperature,concentration,VoltageTemperature,VoltageHydrogen;

    ADC_VoltageGet(&VoltageHydrogen,&VoltageTemperature);
    if(!Data_CalibrationDataUse_Get())
    {
        SystemConfig.DeviceData.VoltageTemperature = VoltageTemperature;
        SystemConfig.DeviceData.VoltageHydrogen = VoltageHydrogen;
        return;
    }
    temperature = Data_CalibrationCalculate_VoltageTemperature(VoltageTemperature,&pos);
    concentration =  Data_CalibrationCalculate_VoltageHydrogen(VoltageHydrogen,pos);

    SystemConfig.DeviceData.VoltageTemperature = VoltageTemperature;
    SystemConfig.DeviceData.VoltageHydrogen = VoltageHydrogen;
    SystemConfig.DeviceData.temperature = temperature;
    SystemConfig.DeviceData.concentration = concentration;
}
